/*************************************************************************
 *  Copyright (C), 2017-2018, Mogoson tech. Co., Ltd.
 *  FileName: AnimatorBehaviour.cs
 *  Author: Mogoson   Version: 1.0   Date: 7/15/2017
 *  Version Description:
 *    Internal develop version,mainly to achieve its function.
 *  File Description:
 *    Ignore.
 *  Class List:
 *    <ID>           <name>             <description>
 *     1.       AnimatorBehaviour          Ignore.
 *  Function List:
 *    <class ID>     <name>             <description>
 *     1.
 *  History:
 *    <ID>    <author>      <time>      <version>      <description>
 *     1.     Mogoson     7/15/2017       1.0        Build this file.
 *************************************************************************/

namespace Developer.AreaRoam
{
    using UnityEngine;

    [AddComponentMenu("Developer/AreaRoam/AnimatorBehaviour")]
    [RequireComponent(typeof(Animator))]
    public class AnimatorBehaviour : MonoBehaviour
    {
        #region Property and Field
        /// <summary>
        /// Behaviours of this game object.
        /// </summary>
        public BehaviourSettings[] behaviours;

        /// <summary>
        /// Current behaviour of this game object.
        /// </summary>
        public BehaviourSettings current { protected set; get; }

        /// <summary>
        /// Timer of behaviour stay.
        /// </summary>
        protected float stayTime = 0;

        /// <summary>
        /// Timer of behaviour.
        /// </summary>
        protected float timer = 0;

        /// <summary>
        /// Animator blend.
        /// </summary>
        protected bool blend = false;

        /// <summary>
        /// Animator blend time.
        /// </summary>
        protected float blendTime = 0.25f;

        /// <summary>
        /// Animator blend velocity.
        /// </summary>
        protected float blendVelocity = 0;

        /// <summary>
        /// Animator of behaviour animation.
        /// </summary>
        protected Animator animator;
        #endregion

        #region Protected Method
        protected virtual void Start()
        {
            animator = GetComponent<Animator>();
            SetBehaviour(behaviours[Random.Range(0, behaviours.Length)]);
        }

        protected virtual void Update()
        {
            BehaviourInArea();
            AnimatorBlend();
        }

        /// <summary>
        /// Set animator parameters.
        /// </summary>
        /// <param name="parameters">Animator parameters.</param>
        protected void SetAnimatorParameters(AnimatorParameters parameters)
        {
            blend = true;
            foreach (var item in parameters.integers)
            {
                animator.SetInteger(item.name.Trim(), item.value);
            }
            foreach (var item in parameters.bools)
            {
                animator.SetBool(item.name.Trim(), item.value);
            }
            foreach (var item in parameters.triggers)
            {
                animator.SetTrigger(item.name.Trim());
            }
        }

        /// <summary>
        /// Override the target speed[example roam speed].
        /// </summary>
        /// <param name="speed">Behaviour speed.</param>
        protected virtual void OverrideSpeed(float speed) { }

        /// <summary>
        /// Behaviour in area.
        /// </summary>
        protected virtual void BehaviourInArea()
        {
            timer += Time.deltaTime;
            if (timer > stayTime)
                SetBehaviour(behaviours[Random.Range(0, behaviours.Length)]);
        }

        /// <summary>
        /// Animator blend.
        /// </summary>
        protected virtual void AnimatorBlend()
        {
            if (blend)
            {
                if (timer <= blendTime + 1)
                {
                    foreach (var item in current.animatorParameters.floats)
                    {
                        animator.SetFloat(item.name.Trim(), Mathf.SmoothDamp(animator.GetFloat(item.name.Trim()), item.value, ref blendVelocity, blendTime));
                    }
                }
                else
                    blend = false;
            }
        }
        #endregion

        #region Public Method
        /// <summary>
        /// Set behaviour of this game object.
        /// </summary>
        /// <param name="behaviour">Behaviour settings.</param>
        public void SetBehaviour(BehaviourSettings behaviour)
        {
            current = behaviour;
            SetAnimatorParameters(current.animatorParameters);
            OverrideSpeed(current.overrideSpeed);
            stayTime = Random.Range(current.stayTime.min, current.stayTime.max);
            timer = 0;
        }
        #endregion
    }//class_end
}//namespace_end